package demo.codeanalyzer.processor;

import java.util.ArrayList;
import java.util.List;

import javax.lang.model.element.Element;
import javax.lang.model.element.Name;

import com.sun.source.tree.ClassTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.Trees;

public class RdfCodeGenerator extends BaseCodeGenerator implements
		CodeGenerator {

	private List<String> properties = new ArrayList<String>();

	public Object printClass(ClassTree classTree, Trees trees) {
		printRdfElementHeader(trees);
		Object result = printRdfElementBody(classTree, trees);
		for (String property : properties) {
			System.out.println(property);
		}
		properties.clear();
		return result;
	}

	public void printMethod(MethodTree methodTree) {
		String methodName = methodTree.getName().toString();
		if (!"<init>".equals(methodName)) {
			System.out.println("Method : " + methodName);
		}
	}

	public Object printVariable(VariableTree variableTree, Trees trees) {
		Name name = variableTree.getName();
		StringBuilder property = new StringBuilder();
		property.append("\n").append(
				String.format("<rdf:Property rdf:ID=\"%s\">", name.toString()));
		property.append("\n").append(
				String.format("<rdfs:range rdf:datatype=%s>", rdfType(trees)));
		Object result = visitor.visitParentVariable(variableTree, trees);
		property.append("\n").append("</rdf:Property>");
		properties.add(property.toString());
		return result;
	}

	protected Object printRdfElementBody(ClassTree classTree, Trees trees) {
		String classDescription = String.format(
				"<rdf:Description rdf:ID=\"%s\">", classTree.getSimpleName());
		System.out.println(classDescription);
		System.out
				.println("<rdf:type rdf:resource=\"http://www.w3.org/2000/01/rdf-schema#Class\"/>");
		Tree extendsClause = classTree.getExtendsClause();
		if (null != extendsClause) {
			System.out.println(String.format(
					"<rdfs:subClassOf rdf:resource=\"#%s\"/>", classTree
							.getExtendsClause().toString()));
		}
		Object result = visitor.visitParentClass(classTree, trees);
		System.out.println("</rdf:Description>");
		return result;
	}

	protected void printRdfElementHeader(Trees trees) {
		String rdfString = String.format(" %s>", namespaceMapping(trees));
		System.out.print(rdfString);
		System.out.println();
	}

	protected String namespaceMapping(Trees trees) {
		String result = annotationValue(element(trees), "namespacemapping");
		if (null == result)
			return "";
		return mappedResult(result);
	}

	private String mappedResult(String result) {
		String[] namespacePairs = result.split(",");
		StringBuilder mapping = new StringBuilder();
		for (String pair : namespacePairs) {
			String[] parts = pair.split("=");
			mapping.append(" ").append(parts[0]).append("=").append(
					quote(parts[1]));
		}
		return unquote(mapping.toString());
	}

	private String quote(String string) {
		return "\"" + string + "\"";
	}

	private String uri(Trees trees) {
		return annotationValue(element(trees), "uri");
	}

	private String nameSpace(Trees trees) {
		return annotationValue(element(trees), "namespace");
	}

	private String resource(Trees trees) {
		return annotationValue(element(trees), "resource");
	}

	private String unquote(String nameSpace) {
		return nameSpace.substring(2, nameSpace.length() - 1);
	}

	private String rdfType(Trees trees) {
		Element element = element(trees);
		if ("java.util.date".equalsIgnoreCase(element.asType().toString()))
			return "\"&xsd;date\"";
		if ("int".equalsIgnoreCase(element.asType().toString()))
			return "\"&xsd;integer\"";

		return "";
	}

	private String rdfResource(Trees trees) {
		String result = resource(trees);
		if (null != result)
			return " rdf:resource=" + result;
		return "";
	}

	public Object printEnum(ClassTree classTree, Trees trees) {
		// TODO Auto-generated method stub
		return null;
	}

	public Object printNamespaces(ClassTree classTree, Trees trees) {
		// TODO Auto-generated method stub
		return null;
	}

	public Object processNamespaces() {
		// TODO Auto-generated method stub
		return null;
	}

	public Object processNamespaces(VariableTree variableTree, Trees trees) {
		// TODO Auto-generated method stub
		return null;
	}

}
